//
// 升级数据处理逻辑
//
#include "stdinc.h"


/*
 ===============================================================================
						 Functions to be executed from RAM
 ===============================================================================

 All the functions defined below must be executed from RAM exclusively, except
 for the FLASH_WaitForLastOperation function which can be executed from Flash.

 Steps of the execution from RAM differs from one toolchain to another:
 - For IAR Compiler:
	1- Use the __ramfunc keyword in the function declaration to specify that it
	can be executed from RAM.
	This is done within the stm8l15x_flash.c file, and it's conditioned by
	RAM_EXECUTION definition.
	2- Uncomment the "#define RAM_EXECUTION  (1)" line in the stm8l15x.h file, or
   define it in IAR compiler preprocessor to enable the access for the
   __ramfunc functions.

 - Note:
	1- Ignore the IAR compiler warnings, these warnings don't impact the FLASH Program/Erase
	operations.
	The code performing the Flash Program/erase must be executed from RAM; the variables
	initializations don't necessary require the execution from RAM, only CR2 registers
	configuration and data programing must be executed from RAM.
	2- These warnings depends on IAR compiler: as the code generation is made using many
	runtime library functions to keep code size to a minimum.
	3- It is recommended to use High Speed Optimization with IAR (-Ohs), in order
	to reduce the runtime library calls in the generated code.
*/
/// Flash 初始化
void Flash_init() {
	FLASH_DeInit();

	// Define flash programming Time
	FLASH_SetProgrammingTime(FLASH_ProgramTime_Standard);
}

/// Flash 上锁
void Flash_lock() {
	FLASH_Lock(FLASH_MemType_Program);
	while (FLASH_GetFlagStatus(FLASH_FLAG_PUL) != RESET);
}

/// Flash 解锁
void Flash_unlock() {
	FLASH_Unlock(FLASH_MemType_Program);
	while (FLASH_GetFlagStatus(FLASH_FLAG_PUL) == RESET);
}

/// 写 Flash 数据块
uint8_t Flash_writeBlock(uint32_t address, uint8_t blockData[FLASH_PAGE_SIZE], bool verify) {
	uint16_t block = (address - FLASH_PROGRAM_START_PHYSICAL_ADDRESS) / FLASH_BLOCK_SIZE;
	osCritical css;
	uint16_t checksum0, checksum2;

	if(verify) { checksum0 = sumBuff(blockData, FLASH_PAGE_SIZE); }

	// ROM 解锁
	FLASH_Unlock(FLASH_MemType_Program);
	while (FLASH_GetFlagStatus(FLASH_FLAG_PUL) == RESET);

	osCriticalEnter(css);
	FLASH_ProgramBlock(block, FLASH_MemType_Program, FLASH_ProgramMode_Standard, blockData);
	while (FLASH_GetFlagStatus(FLASH_FLAG_HVOFF) == RESET);
	osCriticalLeave(css);

	// ROM 上锁
	FLASH_Lock(FLASH_MemType_Program);
	while (FLASH_GetFlagStatus(FLASH_FLAG_PUL) != RESET);

	if(verify) {
		checksum2 = sumBuff((const uint8_t*)address, FLASH_PAGE_SIZE);
		if(checksum2 != checksum0) { return -1; }
	}

	return 0;
}

osCritical _css_eeprom_lock;

// EEPROM 解锁
void Eeprom_unlock() {
	osCriticalEnter(_css_eeprom_lock);
	FLASH_Unlock(FLASH_MemType_Data);
	while (FLASH_GetFlagStatus(FLASH_FLAG_DUL) == RESET);
}

// EEPROM 上锁
void Eeprom_lock() {
	FLASH_Lock(FLASH_MemType_Data);
	while (FLASH_GetFlagStatus(FLASH_FLAG_DUL) != RESET);
	osCriticalLeave(_css_eeprom_lock);
}

// EEPROM 写
uint8_t Eeprom_write(void *addr, void *buff, size_t len) {
    uint8_t *rom = (uint8_t*)addr;
	uint8_t *data = (uint8_t*)buff;

	Eeprom_unlock(); //{{

    while(len--) {
        //*rom++ = *data++;
		FLASH_ProgramByte((uint32_t)rom++, *data++);
		while(FLASH_GetFlagStatus(FLASH_FLAG_HVOFF) == RESET);
    }

	Eeprom_lock(); //}}

	return 0;
}
